/* 
Copyright (c) 2008 Delio Brignoli

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

*/

#include <avr/pgmspace.h>

#ifndef Assert_h
#define Assert_h

//Un-define the standard 'assert' macro (if it is already defined)
#undef assert

#ifdef __cplusplus
 extern "C" {
#endif 

#ifndef NDEBUG
//Store file name only once per file to save precious space on the device's flash memory
#define assert_filename_init() static const prog_char _assert_filename[] PROGMEM = __FILE__;
#else
#define assert_filename_init() (void(0));
#endif

//Reproduce libc's assert macro behaviour: if NDEBUG is defined assert() becomes a no-op
#ifdef NDEBUG

#define assert(expr) ((void)0)

#else

//Default to libc's assert() behaviour and call abort() when an assertion fails.
//If a _PANIC_FUNC is defined it will be called instead of abort()
#ifndef _PANIC_FUNC
#define _PANIC_FUNC abort()
#endif

#ifndef Assert_c

//Keep only a copy of common strings
extern const prog_char _assert_panic_str[] PROGMEM;
extern const prog_char _assert_assertion_failed_str[] PROGMEM;
extern const prog_char _assert_fmt_str[] PROGMEM;

#endif

//Reproduce the standard behaviour of AVR libc: logging is disabled unless __ASSERT_USE_STDERR
//is defined.
#ifdef __ASSERT_USE_STDERR

#define LOG_ASSERT(expr) {\
		fprintf_P(stderr, _assert_assertion_failed_str);\
		fprintf_P(stderr, _assert_filename);\
		fprintf_P(stderr, _assert_fmt_str, __LINE__);\
		fprintf_P(stderr, PSTR(#expr));\
		fprintf_P(stderr, _assert_panic_str);\
		}

#else

#define LOG_ASSERT(expr) ((void)0)

#endif

#define assert(expr) {\
		if (!(expr)) {\
			LOG_ASSERT(expr);\
			_PANIC_FUNC;\
		}\
	}
#endif

#ifdef __cplusplus
 }
#endif 

#endif